#include "../include/logical_handle.h"
#include "../include/tcp_connection.h"
#include <fstream>
#include "../include/base64.h"
#include "../include/file_transfer.h"

void logical_handle::file_send_apply(std::unordered_map<std::string, std::shared_ptr<std::ofstream>> &file_map, struct full_msg *msg)
{
    nlohmann::json res_json;
    std::string file_hash_id=msg->req_json["file_hash_id"].get<std::string>();
    std::string file_name=msg->req_json["file_name"].get<std::string>();
    std::string client_msg_uuid=msg->req_json["client_msg_uuid"].get<std::string>();
    long long file_size=msg->req_json["file_size"].get<long long>();

    res_json["file_hash_id"]=file_hash_id;
    res_json["client_msg_uuid"]=client_msg_uuid;
    res_json["result"]=true;
    
    if(file_map.count(client_msg_uuid)){
        BOOST_LOG_TRIVIAL(error)<<"在文件发送请求时，发生msg_uuid碰撞了";
        res_json["result"]=false;
        std::string data=res_json.dump();
        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_FILE_SEND_APPLY,data.length(),data.c_str());
        return;
    }
    std::shared_ptr<std::ofstream> file=std::make_shared<std::ofstream>(file_hash_id,std::ios::binary | std::ios::app);


    if(!file->is_open()){
        res_json["result"]=false;
        std::string data=res_json.dump();
        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_FILE_SEND_APPLY,data.length(),data.c_str());
        return;
    }
    file_map[client_msg_uuid]=file;
    
    long long break_point=file->tellp();
    res_json["break_point"]=break_point;
    std::string data=res_json.dump();
    msg->tcp_con->async_write_msg(response_package_id::RESPONSE_FILE_SEND_APPLY,data.length(),data.c_str());


}


void logical_handle::file_slice_send(std::unordered_map<std::string, std::shared_ptr<std::ofstream>> &file_map, struct full_msg * msg)
{
    
    std::string file_hash_id=msg->req_json["file_hash_id"].get<std::string>();
    int file_slice_flag=msg->req_json["file_slice_flag"].get<int>();
    std::string raw_file_data=msg->req_json["file_data"].get<std::string>();
    long long file_slice_start=msg->req_json["file_slice_start"].get<int>();
    long long file_seq=msg->req_json["file_seq"].get<int>();
    std::string client_msg_uuid=msg->req_json["client_msg_uuid"].get<std::string>();
    long long file_slice_size=msg->req_json["file_slice_size"].get<long long>();

    //找到需要写入的文件句柄
    if(!file_map.count(client_msg_uuid)){
        //几乎不可能--暂时无兜底机制
        BOOST_LOG_TRIVIAL(error)<<"收到一个文件切片，但是找不到需要写入的目标";
        return;
    }
    auto file_handler=file_map[client_msg_uuid];

    //加工数据
    //char*file_data=( char *)oceanstar::acl_base64_decode(raw_file_data.c_str(),raw_file_data.length());
    std::string file_data=base64_decode(raw_file_data);
    file_handler->seekp(file_slice_start);
    file_handler->write(file_data.c_str(),file_slice_size); //会先写到应用层缓冲区

    //判断是否是文件最后一片切片
    if(file_slice_flag==recv_file_slice_flag::END){
        file_map.erase(client_msg_uuid);
        nlohmann::json res_json;
        res_json["file_hash_id"]=file_hash_id;
        res_json["transfered_point"]=file_slice_start+file_slice_size;
        res_json["client_msg_uuid"]=client_msg_uuid;
        std::string data=res_json.dump();
        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_FILE_SLICE,data.length(),data.c_str());
        return;
    }

    //判断是否需要发送回包---每10个包回一个
    if(file_seq>0 &&file_seq%RESPONSE_SLICE_FREQUENCY==0){
        nlohmann::json res_json;
        res_json["file_hash_id"]=file_hash_id;
        res_json["transfered_point"]=file_slice_start+file_slice_size;
        res_json["client_msg_uuid"]=client_msg_uuid;
        std::string data=res_json.dump();
        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_FILE_SLICE,data.length(),data.c_str());
        return;
    }
    

}



void logical_handle::file_download_apply(std::unordered_map<std::string,std::shared_ptr<std::ifstream>> &read_file_map,struct full_msg *msg)
{
    std::string file_hash_id=msg->req_json["file_hash_id"].get<std::string>();
    std::string download_uuid=msg->req_json["download_uuid"].get<std::string>();
    std::shared_ptr<std::ifstream> read_handler=nullptr;
    if(read_file_map.count(download_uuid)){
        read_handler=read_file_map[download_uuid];
    }else{
        read_handler=std::make_shared<std::ifstream>(file_hash_id,std::ios::binary);
        if(!read_handler->is_open()){
            BOOST_LOG_TRIVIAL(warning)<<"客户端申请的文件，但是无法打开";
            nlohmann::json res_json;
            res_json["download_uuid"]=download_uuid;
            res_json["result"]=false;
            std::string data=res_json.dump();
            msg->tcp_con->async_write_msg(response_package_id::RESPONSE_DOWNLOAD_ADDPLY,data.length(),data.c_str());
            return;
        }
        read_handler->seekg(0);
        read_file_map[download_uuid]=read_handler;
    }

    //进行发送即可--每次发送2M避免阻塞当前线程的其他任务
    char buffer[BUFFER_SIZE];
    nlohmann::json file_slice;
    file_slice["download_uuid"]=download_uuid;
    file_slice["file_hash_id"]=file_hash_id;
    bool flag=false;
    for(int i=0;i<MAX_SEND_TIMES && !flag;++i){
        long long file_slice_start=read_handler->tellg();
        file_slice["file_slice_start"]=file_slice_start;
        read_handler->read(buffer,BUFFER_SIZE);
        int read_res=read_handler->gcount();
        if(read_res<BUFFER_SIZE){
            file_slice["file_slice_flag"]=recv_file_slice_flag::END;
            flag=true;
        }else{
            file_slice["file_slice_flag"]=recv_file_slice_flag::BEFORE_END;
        }
        //转为base_64编码
        if(read_res==0){
            file_slice["file_data"]="";
        }else{
            
            file_slice["file_data"]=base64_encode(buffer,read_res);
            
        }
        
        file_slice["file_slice_size"]=read_res;
        //序列化后进行发送
        std::string data=file_slice.dump();
        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_DOWNLOAD_SLICE,data.length(),data.c_str());

    }

    if(flag){
        //文件发送完毕
        BOOST_LOG_TRIVIAL(info)<<"一个文件下载成功";
        read_file_map.erase(file_hash_id);
    }else{
        //文件发送失败，还需要将msg加入到任务队列中去----但是需要赋值一份新的
        struct full_msg *copy_msg=new struct full_msg;
        copy_msg->body_len=msg->body_len;
        copy_msg->message_id=msg->message_id;
        copy_msg->req_json=msg->req_json;
        copy_msg->tcp_con=msg->tcp_con;
        file_transfer_thread_pool::get_instance()->deal_task(copy_msg);
    }

    

    

    
}